// 全局状态
let chunks = {};
let totalChunks = 0;
let codeReader = null;
let videoInput = null;
let fileMetadata = null;

// DOM 元素
const startScanBtn = document.getElementById('startScan');
const stopScanBtn = document.getElementById('stopScan');
const scannerVideo = document.getElementById('scanner');
const scanStatusDiv = document.getElementById('scanStatus');
const autoModeCheckbox = document.getElementById('autoMode');
const manualInput = document.getElementById('manualInput');
const parseManualBtn = document.getElementById('parseManual');
const fileInput = document.getElementById('fileInput');
const parseFileBtn = document.getElementById('parseFile');
const restoreBtn = document.getElementById('restoreBtn');
const receivedSpan = document.getElementById('received');
const totalSpan = document.getElementById('total');
const chunkListDiv = document.getElementById('chunkList');
const chunkGridDiv = document.getElementById('chunkGrid');
const progressContainer = document.getElementById('progressContainer');
const logDiv = document.getElementById('log');
const fileInfoDiv = document.getElementById('fileInfo');
const fileNameSpan = document.getElementById('fileName');
const fileSizeSpan = document.getElementById('fileSize');
const fileTypeSpan = document.getElementById('fileType');
const fileCRC32Span = document.getElementById('fileCRC32');

// 初始化
document.addEventListener('DOMContentLoaded', () => {
    updateStatus();
    initTabs();
});

// 初始化标签页功能
function initTabs() {
    const tabBtns = document.querySelectorAll('.tab-btn');
    const tabPanes = document.querySelectorAll('.tab-pane');

    tabBtns.forEach(btn => {
        btn.addEventListener('click', () => {
            const targetTab = btn.getAttribute('data-tab');
            
            // 移除所有活动状态
            tabBtns.forEach(b => b.classList.remove('active'));
            tabPanes.forEach(p => p.classList.remove('active'));
            
            // 激活当前标签页
            btn.classList.add('active');
            document.getElementById(targetTab + '-tab').classList.add('active');
            
            // 如果切换到扫描标签页且正在扫描，停止扫描
            if (targetTab !== 'scan' && codeReader) {
                stopScanning();
            }
        });
    });
}

// 停止扫描的辅助函数
function stopScanning() {
    if (codeReader) {
        codeReader.reset();
        codeReader = null;
    }
    if (videoInput) {
        videoInput.stop();
        videoInput = null;
    }
    scannerVideo.srcObject = null;
    startScanBtn.disabled = false;
    stopScanBtn.disabled = true;
    
    // 更新按钮文本状态和扫描状态
    startScanBtn.textContent = '▶ 开始连续扫码';
    updateScanStatus('ready', '📷 准备扫描二维码', '点击"开始连续扫码"后，将二维码对准摄像头');
}

// 更新扫描状态显示
function updateScanStatus(status, title, message) {
    scanStatusDiv.className = `scan-status ${status}`;
    scanStatusDiv.innerHTML = `
        <p><strong>${title}</strong></p>
        <p class="scan-hint">${message}</p>
    `;
}

// 开始扫码
startScanBtn.addEventListener('click', async () => {
    codeReader = new ZXing.BrowserQRCodeReader();
    try {
        updateScanStatus('scanning', '🔄 正在启动摄像头...', '请稍等，正在初始化扫描功能');
        
        videoInput = await codeReader.decodeFromVideoDevice(undefined, scannerVideo, (result, err) => {
            if (result) {
                const success = handleQRContent(result.getText());
                if (success) {
                    updateScanStatus('success', '✅ 扫描成功！', '已成功识别一个二维码块');
                    
                    // 根据模式决定是否继续扫描
                    if (!autoModeCheckbox.checked) {
                        setTimeout(() => {
                            stopScanning();
                            log('📷 单次扫描完成，已自动停止');
                        }, 1500);
                    } else {
                        // 连续模式：短暂显示成功状态后继续扫描
                        setTimeout(() => {
                            updateScanStatus('scanning', '🔄 连续扫描中...', '请对准下一个二维码继续扫描');
                        }, 1000);
                    }
                } else {
                    updateScanStatus('error', '❌ 识别失败', '二维码格式不正确，请重新扫描');
                    setTimeout(() => {
                        updateScanStatus('scanning', '🔄 连续扫描中...', '请对准二维码进行扫描');
                    }, 2000);
                }
            }
            if (err && !(err instanceof ZXing.NotFoundException)) {
                console.error(err);
            }
        });
        
        startScanBtn.disabled = true;
        stopScanBtn.disabled = false;
        startScanBtn.textContent = '🔄 扫描中...';
        updateScanStatus('scanning', '🔄 连续扫描中...', '请将二维码对准摄像头进行扫描');
        log('📷 摄像头已启动，开始连续扫描模式...');
    } catch (err) {
        updateScanStatus('error', '❌ 摄像头启动失败', err.message);
        log('❌ 无法访问摄像头：' + err.message);
    }
});

// 停止扫码
stopScanBtn.addEventListener('click', () => {
    stopScanning();
    log('⏹ 扫码已手动停止');
});

// 解析手动输入
parseManualBtn.addEventListener('click', () => {
    const text = manualInput.value;
    const lines = text.split('\n');
    let count = 0;
    for (let line of lines) {
        line = line.trim();
        if (line) {
            if (handleQRContent(line)) count++;
        }
    }
    log(`📥 手动解析了 ${count} 个数据块`);
    manualInput.value = ''; // 清空
});

// 解析文件上传
parseFileBtn.addEventListener('click', () => {
    const file = fileInput.files[0];
    if (!file) {
        log('❌ 请先选择文件');
        return;
    }
    const reader = new FileReader();
    reader.onload = (e) => {
        const text = e.target.result;
        const lines = text.split('\n');
        let count = 0;
        for (let line of lines) {
            line = line.trim();
            if (line) {
                if (handleQRContent(line)) count++;
            }
        }
        log(`📤 从文件解析了 ${count} 个数据块`);
    };
    reader.readAsText(file);
});

// CRC32 计算函数
function calculateCRC32(data) {
    const table = [];
    for (let i = 0; i < 256; i++) {
        let c = i;
        for (let j = 0; j < 8; j++) {
            c = (c & 1) ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1);
        }
        table[i] = c;
    }
    
    let crc = 0 ^ (-1);
    for (let i = 0; i < data.length; i++) {
        crc = (crc >>> 8) ^ table[(crc ^ data[i]) & 0xFF];
    }
    return (crc ^ (-1)) >>> 0;
}

// 还原文件
restoreBtn.addEventListener('click', () => {
    try {
        // 拼接所有块
        let fullEncoded = '';
        for (let i = 1; i <= totalChunks; i++) {
            if (!chunks[i]) {
                throw new Error(`缺失第 ${i} 块数据`);
            }
            fullEncoded += chunks[i];
        }

        log('🔄 开始还原文件...');

        // Base64 解码
        const compressedData = Uint8Array.from(atob(fullEncoded), c => c.charCodeAt(0));

        // 解压（使用 pako 库）
        const originalData = pako.inflate(compressedData);
        log(`📦 解压完成，还原大小：${originalData.length} bytes`);

        // 验证文件完整性
        if (fileMetadata && fileMetadata.crc32) {
            const calculatedCRC32 = calculateCRC32(originalData);
            const expectedCRC32 = parseInt(fileMetadata.crc32, 16);
            
            if (calculatedCRC32 === expectedCRC32) {
                log(`✅ CRC32校验通过：${calculatedCRC32.toString(16).toUpperCase()}`);
            } else {
                log(`❌ CRC32校验失败！期望：${fileMetadata.crc32}，实际：${calculatedCRC32.toString(16).toUpperCase()}`);
                throw new Error('文件完整性校验失败');
            }
        }

        // 验证文件大小
        if (fileMetadata && fileMetadata.size && originalData.length !== fileMetadata.size) {
            log(`⚠️ 文件大小不匹配！期望：${fileMetadata.size}，实际：${originalData.length}`);
        }

        // 创建 Blob 并下载
        const mimeType = fileMetadata ? fileMetadata.type : 'application/octet-stream';
        const fileName = fileMetadata ? fileMetadata.name : 'restored_file.bin';
        
        const blob = new Blob([originalData], { type: mimeType });
        const url = URL.createObjectURL(blob);
        const a = document.createElement('a');
        a.href = url;
        a.download = fileName;
        document.body.appendChild(a);
        a.click();
        document.body.removeChild(a);
        URL.revokeObjectURL(url);

        log(`✅ 文件已还原并下载：${fileName}`);
    } catch (err) {
        log('❌ 还原失败：' + err.message);
    }
});

// 处理单个二维码内容
function handleQRContent(content) {
    const pipes = content.split('|');
    
    // 检查格式：序号/总数|元数据|数据 或 序号/总数|数据（兼容旧格式）
    if (pipes.length < 2) {
        log('⚠️ 格式错误（缺少 |）：' + content.substring(0, 50) + '...');
        return false;
    }

    const header = pipes[0];
    const parts = header.split('/');

    if (parts.length !== 2) {
        log('⚠️ 头部格式错误：' + header);
        return false;
    }

    const index = parseInt(parts[0]);
    const total = parseInt(parts[1]);

    if (isNaN(index) || isNaN(total) || index < 1 || total < 1) {
        log('⚠️ 序号或总数无效：' + header);
        return false;
    }

    let metadata = null;
    let data = '';

    // 判断是新格式还是旧格式
    if (pipes.length === 3) {
        // 新格式：序号/总数|元数据|数据
        try {
            const metadataStr = decodeURIComponent(escape(atob(pipes[1])));
            metadata = JSON.parse(metadataStr);
            data = pipes[2];
            
            // 第一次接收时保存文件元数据
            if (!fileMetadata) {
                fileMetadata = metadata;
                updateFileInfo();
                log(`📋 接收到文件信息：${metadata.name} (${metadata.size} bytes, ${metadata.type})`);
                log(`🔐 文件CRC32校验码：${metadata.crc32}`);
            }
        } catch (err) {
            log('⚠️ 元数据解析失败：' + err.message);
            return false;
        }
    } else {
        // 旧格式：序号/总数|数据
        data = pipes[1];
    }

    if (totalChunks === 0) {
        totalChunks = total;
        totalSpan.textContent = total;
    } else if (totalChunks !== total) {
        log(`⚠️ 总块数不一致：当前 ${totalChunks}，新块声明 ${total}`);
    }

    chunks[index] = data;
    updateStatus();
    updateChunkList();

    const fileName = fileMetadata ? fileMetadata.name : '未知文件';
    const received = Object.keys(chunks).length;
    log(`✅ 收到第 ${index} 块（共 ${total} 块）- ${fileName} [进度: ${received}/${total}]`);
    
    // 检查是否完成
    if (received === total) {
        updateScanStatus('success', '🎉 所有块已接收完成！', '可以点击"还原并下载文件"按钮完成文件恢复');
        log('🎉 所有数据块已接收完成，可以进行文件还原！');
    }

    return true;
}

// 更新状态显示
function updateStatus() {
    const received = Object.keys(chunks).length;
    receivedSpan.textContent = received;
    restoreBtn.disabled = (received !== totalChunks) || totalChunks === 0;
}

// 更新已接收块列表
function updateChunkList() {
    if (totalChunks === 0) {
        progressContainer.style.display = 'none';
        return;
    }
    
    progressContainer.style.display = 'block';
    
    // 更新网格显示
    chunkGridDiv.innerHTML = '';
    for (let i = 1; i <= totalChunks; i++) {
        const box = document.createElement('div');
        box.className = `chunk-box ${chunks[i] ? 'received' : 'missing'}`;
        box.textContent = i;
        box.title = `块 ${i}: ${chunks[i] ? '已接收' : '未接收'}`;
        
        // 点击切换详细列表显示
        box.addEventListener('click', () => {
            chunkListDiv.classList.toggle('show');
        });
        
        chunkGridDiv.appendChild(box);
    }
    
    // 更新详细列表
    chunkListDiv.innerHTML = '';
    for (let i = 1; i <= totalChunks; i++) {
        const div = document.createElement('div');
        div.innerHTML = `块 ${i}: ${chunks[i] ? '<span style="color: #28a745;">✅ 已接收</span>' : '<span style="color: #dc3545;">❌ 未接收</span>'}`;
        chunkListDiv.appendChild(div);
    }
}

// 更新文件信息显示
function updateFileInfo() {
    if (fileMetadata) {
        fileInfoDiv.style.display = 'block';
        fileNameSpan.textContent = fileMetadata.name;
        fileSizeSpan.textContent = formatFileSize(fileMetadata.size);
        fileTypeSpan.textContent = fileMetadata.type;
        fileCRC32Span.textContent = fileMetadata.crc32;
    }
}

// 格式化文件大小
function formatFileSize(bytes) {
    if (bytes === 0) return '0 Bytes';
    const k = 1024;
    const sizes = ['Bytes', 'KB', 'MB', 'GB'];
    const i = Math.floor(Math.log(bytes) / Math.log(k));
    return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
}

// 日志输出
function log(message) {
    logDiv.style.display = 'block';
    logDiv.innerHTML = `[${new Date().toLocaleTimeString()}] ${message}<br>` + logDiv.innerHTML;
    console.log(message);
}

// 引入 pako 用于 inflate 解压
document.addEventListener('DOMContentLoaded', () => {
    const script = document.createElement('script');
    script.src = 'pako.min.js';
    script.onload = () => {
        console.log('pako loaded');
    };
    document.head.appendChild(script);
});